package com.moleq.mgnetwork;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Vector;

/*
 * send and receive file module
 */
public class FileHandler extends Thread
{

	private InetSocketAddress isa;
	private Socket clientSocket;
	public final static int PER_SEND_SIZE = 1024 * 100;
	private int blockNum = 1;
	private DataInputStream clientIn = null;
	private DataOutputStream clientOut = null;
	private ServerSocket sSocket = null;

	public FileHandler()
	{

	}

	public void sendFiles(final String idAddress, final Vector<String> fileLst)
	{

		new Thread()
		{
			@Override
			public void run()
			{
				for (int i = 0; i < fileLst.size(); i++)
				{
					sendFile(idAddress, fileLst.get(i));
				}
			}
		}.start();

	}

	@Override
	public void run()
	{
		super.run();

		try
		{
			sSocket = new ServerSocket(Constant.FILE_HANDLER_PORT);
			System.out.println("File handler socket started ...");
			while (sSocket != null && !sSocket.isClosed())
			{
				Socket socket = sSocket.accept();
				socket.setSoTimeout(5000);
				new SaveFileToDisk(socket).start();

			}

		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	// save file to disk
	private class SaveFileToDisk extends Thread
	{
		public final static int PER_RECEIVE_SIZE = 1024 * 100;
		private Socket socket = null;
		private DataInputStream dis = null;
		private DataOutputStream dos = null;
		private InputStream is = null;
		private OutputStream os = null;

		public SaveFileToDisk(Socket socket)
		{
			this.socket = socket;

			try
			{
				dis = new DataInputStream(socket.getInputStream());
				dos = new DataOutputStream(socket.getOutputStream());
				is = socket.getInputStream();
				os = socket.getOutputStream();
			} catch (IOException e)
			{
				e.printStackTrace();
			}

		}

		public boolean initFile(File tempFile, File parentFile, long fileSize)
		{
			if (tempFile.exists())
			{
				return true;
			}
			if (parentFile.isDirectory())
			{
				creat(tempFile, fileSize);
				return true;
			} else
			{
				boolean isCreate = parentFile.mkdirs();
				if (isCreate)
				{
					creat(tempFile, fileSize);
					return true;
				} else
				{
					return false;
				}
			}
		}

		public void creat(File targetFile, long fileLength)
		{
			long length = fileLength;// 指定写入文件文件大小
			byte[] buffer = new byte[PER_RECEIVE_SIZE];// 缓冲区 1024 bytes
			FileOutputStream fos;
			try
			{
				fos = new FileOutputStream(targetFile);
				while (true)
				{ // 建立缓冲区
					if (length > PER_RECEIVE_SIZE)
					{ // 将缓冲区字节写入文件
						try
						{
							fos.write(buffer);// 写入缓冲
							length = length - PER_RECEIVE_SIZE;
						} catch (IOException e)
						{
							e.printStackTrace();
						}
					} else
					{
						byte[] buf = new byte[(int) length];
						System.arraycopy(buffer, 0, buf, 0, (int) length);
						try
						{
							fos.write(buf);
							fos.close();
						} catch (IOException e)
						{
							e.printStackTrace();
						}
						break;
					}
				}
			} catch (FileNotFoundException e1)
			{
				e1.printStackTrace();
			}
		}

		public boolean isContinue(DataInputStream dis)
		{
			boolean flag = false;
			String command;
			try
			{
				command = dis.readUTF();
				System.out.println(command);
				if ("Continue".equals(command))
				{
					flag = true;
				}
			} catch (IOException e)
			{
				e.printStackTrace();
				flag = false;
			}
			return flag;
		}

		public void closeSocket(DataInputStream serverIn,
				DataOutputStream serverOut, Socket socket) throws IOException
		{
			if (serverIn != null)
			{
				serverIn.close();
			}
			if (serverOut != null)
			{
				serverOut.close();
			}
			if (socket != null)
			{
				socket.close();
			}
		}

		@Override
		public void run()
		{
			super.run();

			try
			{
				System.out.println("ssss");
				String command = "";
				byte[] buf  = new byte[10000];
				int length = 0;
				while ( (length=is.read(buf, 0, buf.length)) != -1)
				{
					command = new String(buf, 0, length);
				}
				//String command = dis.readUTF();
				System.out.println(command);
				DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
				if (command == null || !command.contains("MoleQInfo"))
				{
					return;
				}
				System.out.println("pppppp");
				String fileName = new String(command
						.replaceAll("(.+<FileName>|<\\/FileName>\\S+)", "")
						.toString().getBytes("UTF-8"), "UTF-8");
				String fileSize = new String(command
						.replaceAll("(.+<FileLength>|<\\/FileLength>\\S+)", "")
						.toString().getBytes("UTF-8"), "UTF-8");
				String offset = new String(
						command.replaceAll(
								"(.+<FilePointerStart>|<\\/FilePointerStart>\\S+)",
								"").toString().getBytes("UTF-8"), "UTF-8");
				String endset = new String(command
						.replaceAll(
								"(.+<FilePointerEnd>|<\\/FilePointerEnd>\\S+)",
								"").toString().getBytes("UTF-8"), "UTF-8");

				File tempFile = new File(Constant.SDCARD_IN_BOX, fileName
						+ ".temp");
				File parentFile = tempFile.getParentFile();
				boolean isCreate = initFile(tempFile, parentFile,
						Long.valueOf(fileSize));
				if (!isCreate)
				{
					closeSocket(dis, dos, socket);
				}
				String readyCommand = "ready=1";
				
				//writeUTF(dos, readyCommand);
				System.out.println(readyCommand);
				InputStream inputStream = new ByteArrayInputStream(readyCommand.getBytes());
				int temp = 0;
				byte[] buff = new byte[1024];
				while ((temp = inputStream.read(buff)) != -1)
				{
					os.write(buff, 0, temp);
					System.out.println(new String(buff, 0, temp));
				}
				
				String startCommand = readUTF(dis);
				if ("sendStart".contains(startCommand))
				{
					RandomAccessFile randomAccessFile = new RandomAccessFile(
							tempFile, "rw");

					long curPoint = Long.valueOf(offset);
					long endPoint = Long.valueOf(endset);
					byte[] buffer = null;
					while (curPoint < endPoint && isContinue(dis))
					{
						if ((endPoint - curPoint + 1 < PER_RECEIVE_SIZE))
						{
							buffer = new byte[(int) (endPoint - curPoint + 1)];
						} else
						{
							buffer = new byte[(int) (PER_RECEIVE_SIZE)];
						}
						int amount;
						long perLength = 0;
						while ((amount = dis.read(buffer)) != -1)
						{
							randomAccessFile.seek(curPoint);
							randomAccessFile.write(buffer, 0, amount);
							curPoint += amount;
							perLength += amount;
							if (perLength == buffer.length)
							{
								break;
							} else if (perLength > buffer.length)
							{
								System.out.println("perLength" + perLength
										+ "\tbuffer" + buffer.length);
								System.out.println("传输出错");
							}
						}
						System.out.println(" 指针位置 " + curPoint + " , 大小"
								+ fileSize + "\t" + (curPoint == endPoint)
								+ "\tendPoint:" + endPoint);
						writeUTF(dos, "SerGotIt");
						if (curPoint == endPoint + 1)
						{
							writeUTF(dos, "receiveEnd");

							// closeRandomAccessFile(randomAccessFile);
							randomAccessFile.close();

							// ******* Ming *****
							if (tempFile.exists())
							{
								File newFile = new File(Constant.SDCARD_IN_BOX,
										fileName);
								tempFile.renameTo(newFile);
							}

							// ******************
							break;
						} else if (curPoint > endPoint)
						{
							System.out.println("curPoint" + curPoint
									+ "\tendPoint" + endPoint);
							System.out.println("文件传输出错");
							break;
						}
					}
				}

			} catch (SocketException e)
			{
				System.out.println("client is closed!");
				// clients.remove(this);
			} catch (EOFException e)
			{
				System.out.println("client is closed!");
				// clients.remove(this);
			} catch (IOException e)
			{
				e.printStackTrace();
			} finally
			{
				try
				{
					if (dis != null)
						dis.close();
					if (dos != null)
						dos.close();
					if (socket != null)
						socket.close();
				} catch (IOException e)
				{
					e.printStackTrace();
				}
			}
		}

	}


	
	public void writeUTF(DataOutputStream dos, String command)
			throws IOException
	{
		dos.writeUTF(command);
		dos.flush();
	}

	public void writeBuffer(DataOutputStream dos, byte[] buffer)
			throws IOException
	{
		dos.write(buffer);
		dos.flush();
	}

	public String readUTF(DataInputStream dis) throws IOException
	{
		return dis.readUTF();
	}

	public String[] getFileInfos(String fileName, long offset, long endset,
			long fileSize, long lastModifyTime)
	{
		String[] fileInfos = new String[blockNum];
		fileInfos[0] = "MoleQInfo";
		fileInfos[0] += "<FileName>" + fileName + "</FileName>";
		fileInfos[0] += "<FilePointerStart>" + offset + "</FilePointerStart>";
		fileInfos[0] += "<FilePointerEnd>" + endset + "</FilePointerEnd>";
		fileInfos[0] += "<FileLength>" + fileSize + "</FileLength>";
		fileInfos[0] += "<LastModifyTime>" + lastModifyTime
				+ "</LastModifyTime>";
		return fileInfos;
	}

	public void sendFile(final String terminalIp, final String filePath)
	{

		// OutputStream output = null;
		// InputStream input = null;

		try
		{

			clientSocket = new Socket();
			isa = new InetSocketAddress(terminalIp, Constant.FILE_HANDLER_PORT);
			clientSocket.connect(isa, 5000);

			if (clientSocket.isConnected())
			{

				InputStream input = clientSocket.getInputStream();
				OutputStream output = clientSocket.getOutputStream(); // 发送文件
				clientIn = new DataInputStream(new BufferedInputStream(input));
				clientOut = new DataOutputStream(new BufferedOutputStream(
						output));
				File tempFile = new File(filePath);
				String fileName = tempFile.getName();

				long fileSize = tempFile.length();
				long lastModifyTime = tempFile.lastModified();
				long offset = 0; // 区块起始位置
				long endset = fileSize - 1; // 区块结束位置
				String[] fileInfos = getFileInfos(fileName, offset, endset,
						fileSize, lastModifyTime);
				writeUTF(clientOut, fileInfos[0]);
				while (true)
				{
					String command = readUTF(clientIn);
					if (!command.contains("ready=1"))
					{
						continue;
					}
					writeUTF(clientOut, "sendStart");
					RandomAccessFile randomAccessFile = new RandomAccessFile(
							tempFile, "r");
					long curPoint = offset;
					byte[] buffer = null;
					while (curPoint < endset)
					{
						writeUTF(clientOut, "Continue");
						int length = 0;
						try
						{
							randomAccessFile.seek(curPoint);
							if (endset - curPoint + 1 < PER_SEND_SIZE)
							{
								buffer = new byte[(int) (endset - curPoint + 1)];
							} else
							{
								buffer = new byte[PER_SEND_SIZE];
							}
							length = randomAccessFile.read(buffer);
							if (length == buffer.length)
							{
								writeBuffer(clientOut, buffer);
								for (;;)
								{
									String serGotItCommand = readUTF(clientIn);
									if ("SerGotIt".equals(serGotItCommand))
									{
										break;
									}
								}
								curPoint += length;
								System.out.println("curPoint:" + curPoint
										+ "\tfileSize:" + fileSize);
								if (curPoint == fileSize)
								{
									System.out.println("发送完成");
									break;
								}
							}
						} catch (Exception e)
						{
							e.printStackTrace();
							break;
						}
					}
					String endCommand = readUTF(clientIn);
					System.out.println(endCommand);
					if ("receiveEnd".equals(endCommand))
					{
						System.out.println("发送指令完成");
						writeUTF(clientOut, "sendEnd");
						tempFile.delete();
						break;
					}
				}
			}

		} catch (Exception e)
		{
			e.printStackTrace();
		} finally
		{
			try
			{
				if (clientIn != null)
				{
					clientIn.close();
				}
				if (clientOut != null)
				{
					clientOut.close();
				}
				if (clientSocket != null)
				{
					clientSocket.close();
				}
			} catch (Exception e)
			{
				e.printStackTrace();
			}
		}

	}

	public void release()
	{
		try
		{
			if (clientIn != null)
			{
				clientIn.close();
			}
			if (clientOut != null)
			{
				clientOut.close();
			}
			if (clientSocket != null)
			{
				clientSocket.close();
			}

			if (sSocket != null)
			{
				sSocket.close();
			}

		} catch (Exception e)
		{
			e.printStackTrace();
		}

	}

}
